
package com.trydofor.id.exec;

import java.net.SocketAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.mina.core.service.IoServiceStatistics;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import com.trydofor.aloe.exception.Exceptions;
import com.trydofor.id.doer.shell.ArgChecker;
import com.trydofor.id.doer.shell.Command;
import com.trydofor.id.doer.shell.Executer;
import com.trydofor.id.doer.shell.Outcome;

/**
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public class ServerExe implements Executer {
    
    private static final DateFormat                  DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    private final Command                            serverStatus;
    private final Command                            listSessions;
    private final Command                            serverBounds;
    
    private final AtomicReference<NioSocketAcceptor> serverReference;
    
    private synchronized String ms(long ms) {
        return DATEFORMAT.format(new Date(ms));
    }
    
    /**
     * constructor
     * 
     * @param server the server
     * @throws NullPointerException if server is null
     */
    public ServerExe(AtomicReference<NioSocketAcceptor> server) {
        Exceptions.checkNullPointer(server);
        this.serverReference = server;
        this.serverStatus = ServerCmd.serverStatus();
        this.listSessions = ServerCmd.listSessions();
        this.serverBounds = ServerCmd.serverBounds();
    }
    
    /**
     * {@inheritDoc}
     */
    public Outcome execute(Command command, Map<String, String> argdata) {
        
        String err = ArgChecker.check(command, argdata);
        if (err != null) return new Outcome(-1, null, err);
        
        if (serverStatus.getAlias().equals(command.getAlias())) {
            return serverStatus(command, argdata);
        }
        else if (listSessions.getAlias().equals(command.getAlias())) {
            return listSessions(command, argdata);
        }
        else if (serverBounds.getAlias().equals(command.getAlias())) {
            return serverBounds(command, argdata);
        }
        return new Outcome(-1, null, "Command is unsupported:" + command);
    }
    
    // ------------------
    private Outcome serverStatus(Command command, Map<String, String> argdata) {
        StringBuilder sb = new StringBuilder();
        int status = 0;
        NioSocketAcceptor server = serverReference.get();
        if (server != null) {
            sb.append("LocalAddress=").append(server.getLocalAddress()).append('\n');
            sb.append("ActivationTime=").append(ms(server.getActivationTime())).append('\n');
            sb.append("ManagedSessionCount=").append(server.getManagedSessionCount()).append('\n');
            sb.append("ScheduledWriteMessages=").append(server.getScheduledWriteMessages()).append('\n');
            
            IoServiceStatistics stat = server.getStatistics();
            
            sb.append("CumulativeManagedSessionCount=")
              .append(stat.getCumulativeManagedSessionCount())
              .append('\n');
            sb.append("LargestManagedSessionCount=")
              .append(stat.getLargestManagedSessionCount())
              .append('\n');
            sb.append("LargestReadBytesThroughput=")
              .append(stat.getLargestReadBytesThroughput())
              .append('\n');
            sb.append("LargestReadMessagesThroughput=")
              .append(stat.getLargestReadMessagesThroughput())
              .append('\n');
            sb.append("LargestWrittenBytesThroughput=")
              .append(stat.getLargestWrittenBytesThroughput())
              .append('\n');
            sb.append("LargestWrittenMessagesThroughput=")
              .append(stat.getLargestWrittenMessagesThroughput())
              .append('\n');
            sb.append("LastIoTime=").append(ms(stat.getLastIoTime())).append('\n');
            sb.append("LastReadTime=").append(ms(stat.getLastReadTime())).append('\n');
            sb.append("LastWriteTime=").append(ms(stat.getLastWriteTime())).append('\n');
            sb.append("ReadBytes=").append(stat.getReadBytes()).append('\n');
            sb.append("ReadBytesThroughput=").append(stat.getReadBytesThroughput()).append('\n');
            sb.append("ReadMessages=").append(stat.getReadMessages()).append('\n');
            sb.append("ReadMessagesThroughput=").append(stat.getReadMessagesThroughput()).append('\n');
            sb.append("ScheduledWriteBytes=").append(stat.getScheduledWriteBytes()).append('\n');
            sb.append("ScheduledWriteMessages=").append(stat.getScheduledWriteMessages()).append('\n');
            sb.append("ThroughputCalculationInterval=")
              .append(stat.getThroughputCalculationInterval())
              .append('\n');
            sb.append("ThroughputCalculationIntervalInMillis=")
              .append(stat.getThroughputCalculationIntervalInMillis())
              .append('\n');
            sb.append("WrittenBytes=").append(stat.getWrittenBytes()).append('\n');
            sb.append("WrittenBytesThroughput=").append(stat.getWrittenBytesThroughput()).append('\n');
            sb.append("WrittenMessages=").append(stat.getWrittenMessages()).append('\n');
            sb.append("WrittenMessagesThroughput=").append(stat.getWrittenMessagesThroughput()).append('\n');
        }
        else {
            sb.append("server is null");
        }
        return new Outcome(status, sb.toString(), null);
    }
    
    private Outcome listSessions(Command command, Map<String, String> argdata) {
        StringBuilder sb = new StringBuilder();
        int status = 0;
        NioSocketAcceptor server = serverReference.get();
        if (server != null) {
            Map<Long, IoSession> ss = server.getManagedSessions();
            for (Entry<Long, IoSession> e : ss.entrySet()) {
                IoSession s = e.getValue();
                sb.append(e.getKey())
                  .append(":")
                  .append(s.getRemoteAddress() + "->" + s.getLocalAddress())
                  .append('\n');
            }
        }
        else {
            status = -1;
            sb.append("server is null");
        }
        return new Outcome(status, sb.toString(), null);
    }
    
    private Outcome serverBounds(Command command, Map<String, String> argdata) {
        StringBuilder sb = new StringBuilder();
        int status = 0;
        NioSocketAcceptor server = serverReference.get();
        if (server != null) {
            for (SocketAddress s : server.getLocalAddresses()) {
                sb.append(s).append('\n');
            }
        }
        else {
            status = -1;
            sb.append("server is null");
        }
        return new Outcome(status, sb.toString(), null);
    }
}
